﻿using System;
using System.Collections.Generic;
using System.Text;

namespace SH
{
    using shPoint2D = shPoint2<uint>;

    using shPoint3D = shPoint3<uint>   ;

    using shVectorI2 =shVector2<int>   ;
    using shVectorU2 =shVector2<uint>  ;
    using shVectorF2 =shVector2<float> ;

    using shVectorI3 =shVector3<int>   ;
    using shVectorU3 =shVector3<uint>  ;
    using shVectorF3 =shVector3<float>  ;

    using shRectI =shRect<int>  ;
    using shRectU =shRect<uint> ;
    using shRectF =shRect<float>  ;

    using shBoxI2 =shBox2<int>  ;
    using shBoxf2 =shBox2<float> ;
    using shBoxU2 =shBox2<uint>  ;
    using shBoxI3 =shBox3<int>  ;
    using shBoxF3 =shBox3<float> ;
    using shBoxU3 =shBox3<uint> ;

    public class shPoint2<_Tx> : shISerializeable where _Tx : struct
    {
        _Tx x;
        _Tx y;

        public shPoint2() { }
        public shPoint2(_Tx x1, _Tx y1)
        {
            x = x1;
            y = y1;
        }

        public shISerializer serialize(shISerializer sc)
        {
            sc.serialize(ref x);
            sc.serialize(ref y);
            return sc;
        }
        public _Tx this[int i]
        {
            get
            {
                if (i == 0) return x;
                else return y;

            }

            set
            {
                if (i == 0) x = value;
                else y = value;

            }
        }
        void Set(_Tx x1, _Tx y1)
        {
            x = x1;
            y = y1;
        }
    }

    public class shPoint3<_Tx> : shISerializeable where _Tx : struct
    {
        _Tx x;
        _Tx y;
        _Tx z;

        public shPoint3() { }
        public shPoint3(_Tx x1, _Tx y1, _Tx z1)
        {
            x = x1;
            y = y1;
            z = z1;
        }

        public shISerializer serialize(shISerializer sc)
        {
            sc.serialize(ref x);
            sc.serialize(ref y);
            sc.serialize(ref z);
            return sc;
        }

        public void Set(_Tx x1, _Tx y1, _Tx z1)
        {
            x = x1;
            y = y1;
            z = z1;
        }

        public _Tx this[int i]
        {
            get
            {
                if (i == 0) return x;
                else if (i == 1) return y;
                else return z;
            }

            set {
                if (i == 0) x = value;
                else if (i == 1) y = value;
                else z = value;
            }
        }
    }

    public class shVector2<_Tx> : shISerializeable where _Tx : struct
    {
        _Tx x;
        _Tx y;
        public shVector2() { }

        public shVector2(_Tx x1, _Tx y1)
        {
            x = x1;
            y = y1;
        }

        public shISerializer serialize(shISerializer sc)
        {

            sc.serialize(ref x);
            sc.serialize(ref y);

            return sc;
        }

        public _Tx X { get => x; set => x = value; }

        public _Tx Y { get => y; set => y = value; }
        public _Tx this[int i]
        {
            get
            {
                if (i == 0) return x;
                else return y;

            }

            set
            {
                if (i == 0) x = value;
                else y = value;

            }
        }

        public void Set(_Tx x1, _Tx y1)
        {
            x = x1;
            y = y1;

        }

        public void Add(shVector2<_Tx> v)
        {
            dynamic x1 = v.x;
            dynamic y1 = v.y;

            x += x1;
            y += y1;

        }

        public void Sub(shVector2<_Tx> v)
        {
            dynamic x1 = v.x;
            dynamic y1 = v.y;
            x -= x1;
            y -= y1;
        }

        public void Min(shVector2<_Tx> v)
        {
            dynamic x1 = v.x;
            dynamic y1 = v.y;
            dynamic x2 = x;
            dynamic y2 = y;

            x = Math.Min(x2, x1);
            y = Math.Min(y2, y1);
        }

        public void Max(shVector2<_Tx> v)
        {
            dynamic x1 = v.x;
            dynamic y1 = v.y;
            dynamic x2 = x;
            dynamic y2 = y;

            x = Math.Max(x2, x1);
            y = Math.Max(y2, y1);
        }

        public long Sum()
        {
            dynamic x2 = x;
            dynamic y2 = y;

            long nSize = x2;
            nSize += y2;

            return nSize;
        }
    }

    public class shVector3<_Tx> : shISerializeable where _Tx : struct
    {
        _Tx x = new _Tx();
        _Tx y = new _Tx();
        _Tx z = new _Tx();
        public shVector3() { }

        public shVector3(_Tx x1, _Tx y1, _Tx z1)
        {
            x = x1;
            y = y1;
            z = z1;
        }

        public shISerializer serialize(shISerializer sc)
        {

            sc.serialize(ref x);
            sc.serialize(ref y);
            sc.serialize(ref z);

            return sc;
        }
        public _Tx X { get => x; set => x = value; }

        public _Tx Y { get => y; set => y = value; }

        public _Tx Z { get => z; set => z = value; }
        public _Tx this[int i]
        {
            get
            {
                if (i == 0) return x;
                else if (i == 1) return y;
                else return z;
            }

            set
            {
                if (i == 0) x = value;
                else if (i == 1) y = value;
                else z = value;
            }
        }

        public void Set(_Tx x1, _Tx y1, _Tx z1)
        {
            x = x1;
            y = y1;
            z = z1;
        }
        public void Add(shVector3<_Tx> v)
        {
            dynamic x1 = v.x;
            dynamic y1 = v.y;
            dynamic z1 = v.z;
            x += x1;
            y += y1;
            z += z1;

        }

        public void Sub(shVector3<_Tx> v)
        {
            dynamic x1 = v.x;
            dynamic y1 = v.y;
            dynamic z1 = v.z;
            x -= x1;
            y -= y1;
            z -= z1;
        }

        public void Min(shVector3<_Tx> v)
        {
            dynamic x1 = v.x;
            dynamic y1 = v.y;
            dynamic z1 = v.z;
            dynamic x2 = x;
            dynamic y2 = y;
            dynamic z2 = z;

            x = Math.Min(x2, x1);
            y = Math.Min(y2, y1);
            z = Math.Min(z2, z1);
        }

        public void Max(shVector3<_Tx> v)
        {
            dynamic x1 = v.x;
            dynamic y1 = v.y;
            dynamic z1 = v.z;
            dynamic x2 = x;
            dynamic y2 = y;
            dynamic z2 = z;

            x = Math.Max(x2, x1);
            y = Math.Max(y2, y1);
            z = Math.Max(z2, z1);
        }

        public long Sum()
        {
            dynamic x2 = x;
            dynamic y2 = y;
            dynamic z2 = z;
            long nSize = x2;
            nSize += y2;
            nSize += z2;

            return nSize;
        }

    }

    public class shRect<_Tx> : shISerializeable where _Tx : struct
    {
        shVector2<_Tx> pt = new shVector2<_Tx>();
        shVector2<_Tx> size = new shVector2<_Tx>();

        public shRect()
        {
        }

        public shRect(_Tx x1, _Tx y1, _Tx x2, _Tx y2)
        {
            pt.Set(x1, y1);
            size.Set(x2, y2);
        }

        public shISerializer serialize(shISerializer sc)
        {
            sc.serialize(pt);
            sc.serialize(size);

            return sc;
        }

        public shPoint2<_Tx> this[int index]
        {
            get
            {
                switch (index)
                {
                    case 0:
                        return LeftTop();
                    case 1:
                        return RightTop();
                    case 2:
                        return LeftBottom();
                    case 3:
                        return RightBottom();
                    default:
                        return new shPoint2<_Tx>();
                }
            }

        }


        public bool IsNull()
        {
            dynamic x1 = pt.X;
            dynamic x2 = size.X;

            if (x1 < x2) return false;

            dynamic y1 = size.Y;
            dynamic y2 = pt.Y;

            if (y1 < y2) return false;

            return true;
        }

        public _Tx Width
        {
            get => size.X;
        }

        public _Tx Height
        {
            get => size.Y;
        }

        public _Tx X
        {
            get => X;
        }

        public _Tx Y
        {
            get => Y;
        }


        public shPoint2<_Tx> LeftTop()
        {
            return new shPoint2<_Tx>(pt.X, pt.Y);
        }

        shPoint2<_Tx> RightTop()
        {
            dynamic x1 = pt.X;
            dynamic x2 = size.X;

            return new shPoint2<_Tx>(x1 + x2, size.Y);
        }

        shPoint2<_Tx> LeftBottom()
        {
            dynamic y1 = pt.Y;
            dynamic y2 = size.Y;

            return new shPoint2<_Tx>(pt.X, y1 + y2);
        }

        shPoint2<_Tx> RightBottom()
        {
            dynamic x1 = pt.X;
            dynamic x2 = size.X;
            dynamic y1 = pt.Y;
            dynamic y2 = size.Y;
            return new shPoint2<_Tx>(x1 + x2, y1 + y2);
        }

    };

    public class shBox2<_Tx> : shISerializeable where _Tx : struct
    {
        shVector2<_Tx> m_min = new shVector2<_Tx>();
        shVector2<_Tx> m_max = new shVector2<_Tx>();

        public shBox2()
        {
        }

        public shBox2(_Tx x1, _Tx y1, _Tx x2, _Tx y2)
        {
            m_min.Set(x1, y1);
            m_max.Set(x2, y2);
        }

        public shISerializer serialize(shISerializer sc)
        {
            sc.serialize(m_min);
            sc.serialize(m_max);

            return sc;
        }

        public shPoint2<_Tx> this[int index]
        {
            get {

                switch (index)
                {
                    case 0:
                        return LeftTop();
                    case 1:
                        return RightTop();
                    case 2:
                        return LeftBottom();
                    case 3:
                        return RightBottom();
                    default:
                        return new shPoint2<_Tx>();
                }
            }
        }

        public void MakeEmpty()
        {
            dynamic o = 0;

            m_min.X = m_min.Y = o;
            m_max.X = m_max.Y = o;
        }

        public bool IsNull
        {
            get
            {
                dynamic x1 = m_max.X;
                dynamic x2 = m_min.X;
                dynamic y1 = m_max.Y;
                dynamic y2 = m_min.Y;

                return (x1 <= x2) || (y1 <= y2);
            }
        }

        public void ExpandByVector(shVector2<_Tx> vec2)
        {
            m_min.Sub(vec2);
            m_max.Add(vec2);
        }

        public void Intersect(shBox2<_Tx> box)
        {
            m_min.Max(box.m_min);
            m_max.Min(box.m_max);
        }

        public void Union(shBox2<_Tx> box)
        {
            m_min.Min(box.m_min);
            m_max.Max(box.m_max);
        }
        public shPoint2<_Tx> LeftTop()
        {
            return new shPoint2<_Tx>(m_min.X, m_min.Y);
        }

        public shPoint2<_Tx> RightTop()
        {
            return new shPoint2<_Tx>(m_max.X, m_min.Y);
        }

        public shPoint2<_Tx> LeftBottom()
        {
            return new shPoint2<_Tx>(m_min.X, m_max.Y);
        }

        public shPoint2<_Tx> RightBottom()
        {
            return new shPoint2<_Tx>(m_max.X, m_max.Y);
        }

    };

    public class shBox3<_Tx> : shISerializeable where _Tx : struct
    {
        shVector3<_Tx> m_min = new shVector3<_Tx>();
        shVector3<_Tx> m_max = new shVector3<_Tx>();

        public shBox3()

        {

        }

        public shBox3(_Tx x1, _Tx y1, _Tx z1, _Tx x2, _Tx y2, _Tx z2)
        {
            m_min.Set(x1, y1, z1);
            m_max.Set(x2, y2, z2);
        }


        public shISerializer serialize(shISerializer sc)
        {
            sc.serialize(m_min);
            sc.serialize(m_max);

            return sc;
        }

        public shPoint3<_Tx> this[int index]
        {
            get
            {

                switch (index)
                {
                    case 0: return GetPoint1();
                    case 1: return GetPoint2();
                    default:
                        return new shPoint3<_Tx>();
                }
            }

        }


        public void MakeEmpty()
        {
            dynamic o = 0;

            m_min.X = m_min.Y = m_min.Z = o;
            m_max.X = m_max.Y = m_min.Z = o;
        }

        public void MakeNull()
        {
            dynamic l = 1;

            m_min.X = m_min.Y = m_min.Z = l;
            m_max.X = m_max.Y = m_min.Z = l;
        }

        public bool IsNull
        {
            get {
                dynamic x1 = m_max.X;
                dynamic x2 = m_min.X;
                dynamic z1 = m_max.Z;
                dynamic y1 = m_max.Y;
                dynamic y2 = m_min.Y;
                dynamic z2 = m_min.Z;

                return (x1 <= x2) || (y1 <= y2) || z1 <= z2;
            }
        }

    public void ExpandByVector(shVector3<_Tx> vec3)
    {
        m_min.Sub(vec3);
        m_max.Add(vec3);
    }

    public void Intersect(shBox3<_Tx> box)
    {
        m_min.Max(box.m_min);
        m_max.Min(box.m_max);
    }

    public void Union(shBox3<_Tx> box)
    {
        m_min.Min(box.m_min);
        m_max.Max(box.m_max);
    }

    public shPoint3<_Tx> GetPoint1()
    {
        return new shPoint3<_Tx>(m_min.X, m_min.Y, m_min.Z);
    }


    public shPoint3<_Tx> GetPoint2()
    {
        return new shPoint3<_Tx>(m_max.X, m_max.Y, m_max.Z);
    }
    }

 

}
